//#define WII
/*---------------------------------------------------------------------------------

	wack a mole game V.0.1

	hi the moving cubes as they came out

---------------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
#include <gccore.h>
#include <math.h>
#ifdef WII
#include <wiiuse/wpad.h>
#else
#include <ogc/pad.h>
#endif

#define DEFAULT_FIFO_SIZE	( 256*1024 )

static void *frameBuffer[2] = { NULL, NULL };
GXRModeObj *rmode;


//+ #define ZOOM -20.0f
//+ void DrawMouseCursor(int x, int y){
//+    //Will be transparent
//+    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
//+    glEnable(GL_BLEND);
//+    glDisable(GL_DEPTH_TEST);
//+    
//+    //Draw the cursor at the current mouse pos
//+    glBegin(GL_TRIANGLES);
//+      glColor4f(0.75,0.75,0.75,0.75);
//+      glVertex3f(x , y, ZOOM);
//+      glVertex3f(x , y-0.5f, ZOOM);
//+      glVertex3f(x+0.5f, y, ZOOM);
//+    glEnd();
//+    
//+    //Alles wird wie vorher
//+    glDisable(GL_BLEND);
//+    glEnable(GL_DEPTH_TEST);
//+ }

//---------------------------------------------------------------------------------
int main( int argc, char **argv ){
//---------------------------------------------------------------------------------
	f32 yscale;
	u32 xfbHeight;
	Mtx view, perspective; // view and perspective matrices
	Mtx model, modelview;
	GXColor background = { 0, 0, 0, 0xff };
	VIDEO_Init( );
	rmode = VIDEO_GetPreferredMode( NULL );
	// allocate 2 framebuffers for double buffering
	u32	fb = 0; 	// initial framebuffer index
	frameBuffer[0] = MEM_K0_TO_K1( SYS_AllocateFramebuffer( rmode ) );
	frameBuffer[1] = MEM_K0_TO_K1( SYS_AllocateFramebuffer( rmode ) );
	VIDEO_Configure( rmode );
	VIDEO_SetNextFramebuffer( frameBuffer[fb] );
	VIDEO_SetBlack( FALSE );
	VIDEO_Flush( );
	VIDEO_WaitVSync( );
	if( rmode->viTVMode&VI_NON_INTERLACE ) VIDEO_WaitVSync( );
	// setup the fifo and then init the flipper
	void *gp_fifo = NULL;
	gp_fifo = memalign( 32, DEFAULT_FIFO_SIZE );
	memset( gp_fifo, 0, DEFAULT_FIFO_SIZE );
	GX_Init( gp_fifo, DEFAULT_FIFO_SIZE );
	// clears the bg to color and clears the z buffer
	GX_SetCopyClear( background, 0x00ffffff );
	// other gx setup
	GX_SetViewport( 0, 0, rmode->fbWidth, rmode->efbHeight, 0, 1 );
	yscale = GX_GetYScaleFactor( rmode->efbHeight, rmode->xfbHeight );
	xfbHeight = GX_SetDispCopyYScale( yscale );
	GX_SetScissor( 0, 0, rmode->fbWidth, rmode->efbHeight );
	// all this is used for the double( ? ) framebuffer
	GX_SetDispCopySrc( 0, 0, rmode->fbWidth, rmode->efbHeight );
	GX_SetDispCopyDst( rmode->fbWidth, xfbHeight );
	GX_SetCopyFilter( rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter );
	GX_SetFieldMode( rmode->field_rendering, ( ( rmode->viHeight==2*rmode->xfbHeight )?GX_ENABLE:GX_DISABLE ) );
	GX_SetCullMode( GX_CULL_NONE );
	GX_CopyDisp( frameBuffer[fb], GX_TRUE );
	GX_SetDispCopyGamma( GX_GM_1_0 );
	// setup the vertex descriptor
	// tells the flipper to expect direct data
	GX_ClearVtxDesc( );
	GX_SetVtxDesc( GX_VA_POS, GX_DIRECT );
 	GX_SetVtxDesc( GX_VA_CLR0, GX_DIRECT );
	// setup the vertex attribute table
	// describes the data
	// args: vat location 0-7, type of data, data format, size, scale
	// so for ex. in the first call we are sending position data with
	// 3 values X, Y, Z of size F32. scale sets the number of fractional
	// bits for non float data.
	GX_SetVtxAttrFmt( GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0 );
	GX_SetVtxAttrFmt( GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGB8, 0 );
	GX_SetNumChans( 1 );
	GX_SetNumTexGens( 0 );
	GX_SetTevOrder( GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0 );
	GX_SetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
	// setup our camera at the origin
	// looking down the -z axis with y up
	Vector cam = { 0.0F, 0.0F,  0.0F },
	        up = { 0.0F, 1.0F,  0.0F },
	      look = { 0.0F, 0.0F, -1.0F };
	guLookAt( view, &cam, &up, &look );
	// setup our projection matrix
	// this creates a perspective matrix with a view angle of 90,
	// and aspect ratio based on the display resolution
	f32 w = rmode->viWidth;
	f32 h = rmode->viHeight;
	guPerspective( perspective, 45, ( f32 )w/h, 0.1F, 300.0F );
	GX_LoadProjectionMtx( perspective, GX_PERSPECTIVE );
// ----------------- end opengl initialization black magic --------------
#ifdef WII
	WPAD_Init( );
	WPAD_SetVRes(0, (int)w, (int)h);
	WPAD_SetDataFormat( WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR ); 
	ir_t ir; 
#else
	PAD_Init();
#endif

	// camera movement
	f32 camX = -1;
	f32 camY = -1;
	f32 camZ = -1;
	f32 camA = 0.0f; //rotation angle for the camera on the Y axis. controled by +/- buttons on wii
	f32 camAacc = 0.0f; //aceleration
	// cursor movement
	f32 curX = 0;
	f32 curY = 0;

	// frame count for animations
	f32 frame = -1;
	while( 1 ) {
		frame++; //TODO: some FPS calculations
#ifdef WII
		WPAD_ScanPads( );
		// think the chan_0 means player 1...
		if( WPAD_ButtonsDown( WPAD_CHAN_0 ) & WPAD_BUTTON_HOME ) exit( 0 );
		if( WPAD_ButtonsHeld( WPAD_CHAN_0 ) & WPAD_BUTTON_PLUS ){ camAacc += 0.001f; camA += camAacc; }
		if( WPAD_ButtonsHeld( WPAD_CHAN_0 ) & WPAD_BUTTON_MINUS ){ camAacc += 0.001f; camA -= camAacc; }
		if( WPAD_ButtonsUp( WPAD_CHAN_0 ) & WPAD_BUTTON_MINUS ){ camAacc = 0.0f; }
		if( WPAD_ButtonsUp( WPAD_CHAN_0 ) & WPAD_BUTTON_PLUS ){ camAacc = 0.0f; }
		// ge the IR position
		WPAD_IR(0, &ir);
		if( ir.x > 1)
		curX -= (f32)(ir.x - (f32)(w/2)) / 10000.0F;
		if( ir.y > 1 )
		curY += (f32)(ir.y - (f32)(h/2)) / 10000.0F;
#else // gamecube
		exit(0);
		PAD_ScanPads();
		if (PAD_ButtonsDown(0) & PAD_BUTTON_START) exit( 0 );
		if (PAD_ButtonsHeld(0) & PAD_BUTTON_LEFT){ camAacc += 0.001f; camA += camAacc; }
		if (PAD_ButtonsHeld(0) & PAD_BUTTON_RIGHT){ camAacc += 0.001f; camA -= camAacc; }
		if( PAD_ButtonsUp(0) & PAD_BUTTON_LEFT ){ camAacc = 0.0f; }
		if( PAD_ButtonsUp(0) & PAD_BUTTON_RIGHT ){ camAacc = 0.0f; }
#endif
		if( camAacc > 0.1f ) camAacc = 0.1f;

		// do this before drawing
		GX_SetViewport( 0, 0, rmode->fbWidth, rmode->efbHeight, 0, 1 );
		// camera
		camX = sin( ( camA ) ) * 8; // 8.0f is the radius the came revolve
		camZ = cos( ( camA ) ) * 8;
		// move the look based on the cursor
		// it begins at 0, 0, 0
		// and x and y is affected by the cursor displacement in relation
		// to the screen center
		Vector cam = { camX, camY, camZ },
					 up = { 0, 1.0F, 0.0F },
					 look = { curX, curY, 0.0F };
		     //look = { 0, 0.0F, 0 };
		guLookAt( view, &cam, &up, &look );

		guMtxIdentity( model );

		// cube
		//guMtxTransApply( model, model, -2.0F - cos( ang )*r, sin( ang )*r, 0.5f );
		f32 ang = frame /30.0f;
		guMtxTransApply( model, model, -2.0F - cos( ang )*4.0f, sin( ang )*4.0f, 0.5f );
		guMtxConcat( view, model, modelview );
		// load the modelview matrix into matrix memory
		GX_LoadPosMtxImm( modelview, GX_PNMTX0 );
		// A CUBE! ( witch wacko warner voice ) A CUBE!
		GX_Begin( GX_QUADS, GX_VTXFMT0, 24 );			// Draw A Quad
		// front
			GX_Position3f32( -1.0f, 1.0f, 0.0f );	// Top Left
			GX_Color3f32( 0.0f, 0.0f, 1.0f );			// Set The Color To Blue
			GX_Position3f32( 1.0f, 1.0f, 0.0f );		// Top Right
			GX_Color3f32( 0.0f, 0.0f, 1.0f );			// Set The Color To Blue
			GX_Position3f32( 1.0f, -1.0f, 0.0f );	// Bottom Right
			GX_Color3f32( 0.0f, 0.0f, 1.0f );			// Set The Color To Blue
			GX_Position3f32( -1.0f, -1.0f, 0.0f );	// Bottom Left
			GX_Color3f32( 0.0f, 0.0f, 1.0f );			// Set The Color To Blue
		// top
			GX_Position3f32( 1.0f, 1.0f, -2.0f );
			GX_Color3f32( 0.0f, 1.0f, 1.0f );
			GX_Position3f32( 1.0f, 1.0f, 0.0f );
			GX_Color3f32( 0.0f, 1.0f, 1.0f );
			GX_Position3f32( -1.0f, 1.0f, 0.0f );
			GX_Color3f32( 0.0f, 1.0f, 1.0f );
			GX_Position3f32( -1.0f, 1.0f, -2.0f );
			GX_Color3f32( 0.0f, 1.0f, 1.0f );
		// back
			GX_Position3f32( -1.0f, 1.0f, -2.0f );	// Top Left
			GX_Color3f32( 0.0f, 0.0f, 1.0f );
			GX_Position3f32( 1.0f, 1.0f, -2.0f );		// Top Right
			GX_Color3f32( 0.0f, 0.0f, 1.0f );
			GX_Position3f32( 1.0f, -1.0f, -2.0f );	// Bottom Right
			GX_Color3f32( 0.0f, 0.0f, 1.0f );
			GX_Position3f32( -1.0f, -1.0f, -2.0f );	// Bottom Left
			GX_Color3f32( 0.0f, 0.0f, 1.0f );
		//  left
			GX_Position3f32( -1.0f, 1.0f, 0.0f );	// Top Left
			GX_Color3f32( 1.0f, 0.0f, 0.0f );
			GX_Position3f32( -1.0f, 1.0f, -2.0f );		// Top Right
			GX_Color3f32( 1.0f, 0.0f, 0.0f );
			GX_Position3f32( -1.0f, -1.0f, -2.0f );	// Bottom Right
			GX_Color3f32( 1.0f, 0.0f, 0.0f );
			GX_Position3f32( -1.0f, -1.0f, 0.0f );	// Bottom Left
			GX_Color3f32( 1.0f, 0.0f, 0.0f );
		// right
			GX_Position3f32( 1.0f, 1.0f, 0.0f );	// Top Left
			GX_Color3f32( 1.0f, 0.0f, 0.0f );
			GX_Position3f32( 1.0f, 1.0f, -2.0f );		// Top Right
			GX_Color3f32( 1.0f, 0.0f, 0.0f );
			GX_Position3f32( 1.0f, -1.0f, -2.0f );	// Bottom Right
			GX_Color3f32( 1.0f, 0.0f, 0.0f );
			GX_Position3f32( 1.0f, -1.0f, 0.0f );	// Bottom Left
			GX_Color3f32( 1.0f, 0.0f, 0.0f );
		// bottom
			GX_Position3f32( -1.0f, -1.0f, 0.0f );	// Top Left
			GX_Color3f32( 1.0f, 0.0f, 1.0f );
			GX_Position3f32( 1.0f, -1.0f, 0.0f );		// Top Right
			GX_Color3f32( 1.0f, 0.0f, 1.0f );
			GX_Position3f32( 1.0f, -1.0f, -2.0f );	// Bottom Right
			GX_Color3f32( 1.0f, 0.0f, 1.0f );
			GX_Position3f32( -1.0f, -1.0f, -2.0f );	// Bottom Left
			GX_Color3f32( 1.0f, 0.0f, 1.0f );
		GX_End( );									// Done Drawing The Quad


		// tri
		guMtxTransApply( model, model, 0, 0, 0 );
		guMtxConcat( view, model, modelview );
		// load the modelview matrix into matrix memory
		GX_LoadPosMtxImm( modelview, GX_PNMTX0 );
		GX_Unproject( ir.x, y - ir.y, 0.5f, modelview, projection, view, 0, 0, 0 );
		GX_Begin( GX_TRIANGLES, GX_VTXFMT0, 3 );
			GX_Position3f32( 0.0f, 1.0f, 0.0f );		// Top
			GX_Color3f32( 1.0f, 0.0f, 0.0f );			// Set The Color To Red
			GX_Position3f32( -1.0f, -1.0f, 0.0f );	// Bottom Left
			GX_Color3f32( 0.0f, 1.0f, 0.0f );			// Set The Color To Green
			GX_Position3f32( 1.0f, -1.0f, 0.0f );	// Bottom Right
			GX_Color3f32( 0.0f, 0.0f, 1.0f );			// Set The Color To Blue
		GX_End( );
		// do this stuff after drawing
		GX_DrawDone( );


		fb ^= 1;		// flip framebuffer
		GX_SetZMode( GX_TRUE, GX_LEQUAL, GX_TRUE );
		GX_SetColorUpdate( GX_TRUE );
		GX_CopyDisp( frameBuffer[fb], GX_TRUE );

		VIDEO_SetNextFramebuffer( frameBuffer[fb] );

		VIDEO_Flush( );

		//probably only needed in CRT?
		VIDEO_WaitVSync( );


	 }
	return 0;
 }
